/**
 * 高阶函数概念：如果函数的参数一个函数，或者返回值是一个函数，那么这个函数就是高阶函数
 * 1.回调函数是高阶函数的一种
 * 2.高阶函数都是闭包，闭包的概念：指有权访问到另一个函数作用域中变量的函数，闭包中可以访问到外层函数的作用域
 * 3.闭包产生的原因是，当前环境下存在指向父级作用域的引用
 * 4.闭包表现形式：1) IIFE(立即执行函数表达式) 2) 返回一个函数 3)作为函数参数传递 4)包含回调的函数
 */
// 常见的高阶函数应用：流程传递(涉及传递前事件、传递后事件) 
function pass(initiator, approver) {
  console.log(`${initiator}发起流程，传递给${approver}`)
}
// 最简单给 pass 方法增加 before/after 事件，直接把 before/after 绑定到 Function.prototype
Function.prototype.before = function (beforeCb) {
  // 1.newFn 使用箭头函数调用传递前事件及传递事件，箭头函数没有 this，没有 arguments，没有原型
  // 2.没有 arguments，但是可以使用 ...args 表示剩余参数，把所有剩余参数合并成一个数组，只写 args，只能拿到第一个参数
  return (...args) => {
    console.log(args) // 得到的 args 是一个参数数组，调用 this 传参必须使用 ... 扩展运算符
    beforeCb()
    // this 指向 before 的调用者，相当于 pass，然后传入参数
    console.log(this)
    this(...args)
    // this.apply(void 0, args) void 0 表示传一个 undefined，表示把上下文对象设置为 window
  }
}
let newFn = pass.before(function () {
  console.log('流程传递前')
})
newFn('张三', '李四')

// vue2.0 监听数组变化 数据劫持 拦截七个原型方法：push、pop、shift、unshift、reverse、sort、splice
const arrayMethods = ['push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice']
const arrayArgumentation = []

arrayMethods.forEach(method => {
  // 获取原型上的方法
  let originMethod = Array.prototype[method]
  // 将拦截的方法重写后放到 arrayArgumentation 对象上
  arrayArgumentation[method] = function () {
    // 通知 View 更新等
    console.log('数据被修改了，请更新视图')
    // 返回原型方法调用的结果 this 指向方法调用者(数组)
    return originMethod.apply(this, arguments)
  }
})

// 测试数组原型方法劫持
let list = [1, 2, 3]
list.__proto__ = arrayArgumentation
list.splice(1, 1, 5, 7)
console.log(list)